-- For server only mods, let's just check right at the top if we're running on a client, and return ASAP
--if not (GLOBAL.TheNet and GLOBAL.TheNet:GetIsServer()) then return end

-- Set variables for easier typing later
local _G = GLOBAL
local TheNet = _G.TheNet
local TheWorld = _G.TheWorld
local AllPlayers = _G.AllPlayers
-- NB: this may not be valid here, while player(s) are in the lobby
--local ThePlayer = _G.ThePlayer

--_G.CHEATS_ENABLED = true--disable for push to live
--_G.require( 'debugkeys' )--disable for push to live

-- from PeterA's thread
-- https://forums.kleientertainment.com/topic/48264-net_variable-types-and-sending-data-from-serverhost-to-clients/
--
--|                      | client host | remote client | dedicated |
--------------------------------------------------------------------
--| TheWorld.ismastersim |    true     |     false     |   true    |
--| TheNet.GetIsServer() |    true     |     false     |   true    |
--| TheNet.IsDedicated() |    false    |     false     |   true    |
--| TheNet.GetIsClient() |    false    |     true      |   false   |
local isMaster = TheNet:GetIsMasterSimulation()
local isServer = TheNet:GetIsServer()
local isClient = TheNet:GetIsClient()
local isDedicated = TheNet:IsDedicated()

--modassert(test, message)
-- prints message if test fails, or crashes the game if EnableModError() is set
-- EnableModError is in server_dst/mods/modsettings.lua in my dedicated server
-- Same as normal assert, except EnableModError is off for normal users
--moderror(message)
-- prints message with addl bits, or crashes the game if EnableModError() is set
-- If games state is unrecoverable, use a regular assert() or error()
--modprint(...)
-- prints if mod is enabled


--print(AllPlayers[1]:HasTag("playerghost"))

--AllPlayers[1]:PushEvent("respawnfromghost")
--print(AllPlayers[1].components.health:IsDead())


-- pulls setting for hud configs from modinfo
local layout=GetModConfigData("layout")
local positional=GetModConfigData("position")

--imports partybadge
local phud_custombadge= _G.require("widgets/partybadge")
local phud_xpos=0
local phud_ypos=0

if positional==0 then -- standard with minimap
	phud_xpos= (-100)
	phud_ypos= (-70)
elseif positional==1 then --extra large minimap
	phud_xpos= (-650) 
	phud_ypos= (50)
else --no minimap, put on the righthand side
    phud_xpos= (60) 
    phud_ypos= (-135)
end

--constructor for badge array
local function onstatusdisplaysconstruct(self)
	self.badgearray = {}
		--instance badges for players. 
	for i = 1, (GLOBAL.TheNet:GetDefaultMaxPlayers() - 1), 1 do
		self.badgearray[i]=self:AddChild(phud_custombadge(self,self.owner))

        local myx = 0
        local myy = 0
        local j = i - 1
		if layout==0 then -- Compact Grid
			--complicated spagetti for a  properly aligned 2x3 grid
            -- change this to x - (i%2)*badgewidth, y + (i%2)*badgeheight
            -- change that to x - (i%2)*badgewidth - ((i%2)-1)*spacer, y + (i%2)*badgeheight + ((i%2)-1)*spacer
			--self.badgearray[i]:SetPosition(phud_xpos+(35*(-i-i%2)) ,phud_ypos-110+(110*(-i%2)),0)
            myx = phud_xpos+(35*(-i-i%2))
            myy = phud_ypos-110+(110*(-i%2))
        elseif layout==2 then-- Vertical
			--self.badgearray[i]:SetPosition(phud_xpos,phud_ypos+(70*i),0)
            myx = phud_xpos
            myy = phud_ypos-(70*j)
        elseif layout==3 then-- Alt Grid
            myx = phud_xpos-(70*((j-j%2)/2))
            myy = phud_ypos-(90*(j%2)) -- this was 70 before, which might be find without Combined Status
                                       -- create is serverHasThisMod() function, and set appropriately
		else -- Horizontal
			--self.badgearray[i]:SetPosition(phud_xpos+(-70*i),phud_ypos,0)
            myx = phud_xpos+(-70*i)
            myy = phud_ypos-70
		end
		self.badgearray[i]:SetPosition(myx, myy, 0)
        print("[PartyHUD] Placed badge #"..tostring(i).." at "..tostring(myx)..","..tostring(myy))
	end
	self.owner.UpdateBadgeVisibility = function()
		for i = 1, (GLOBAL.TheNet:GetDefaultMaxPlayers() - 1), 1 do
			self.badgearray[i]:HideBadge()
			--self.badgearray[i]:ShowBadge()

		end
        local sawself = 0 -- have we seen ourself in the loop below
        local j = 0       -- real array index, since we'll be skipping ourself
		for i, v in ipairs(GLOBAL.AllPlayers) do
            if v:GetDisplayName()==GLOBAL.ThePlayer:GetDisplayName() then
                sawself = 1
            else
                j = i - sawself
                local isdead = (v.customisdead and v.customisdead:value() or false)
			    --print("Player "..tostring(i).." Should be dead "..tostring(isdead).." ")
			    if isdead==true then 
				    self.badgearray[j]:ShowDead()
			    else
				    self.badgearray[j]:ShowBadge()
			    end
            end
		end
	end

	--call upon any player healthdelta
	self.owner.UpdateBadges= function()
		if not GLOBAL.ThePlayer then return true end
		--update badges
        local sawself = 0 -- have we seen ourself in the loop below
        local j = 0       -- real array index, since we'll be skipping ourself
		for i, v in ipairs(GLOBAL.AllPlayers) do
            if v:GetDisplayName()==GLOBAL.ThePlayer:GetDisplayName() then
                sawself = 1
            else
                j = i - sawself
			    local percent = v.customhpbadgepercent and (v.customhpbadgepercent:value())/100 or 0
			    local max = v.customhpbadgemax and v.customhpbadgemax:value() or 0
			    local debuff = v.customhpbadgedebuff and v.customhpbadgedebuff:value() or 0
                local namestr = v:GetDisplayName()
			    self.badgearray[j]:SetPercent(percent,max,debuff)
			    if string.len(namestr) > 8 then
			    	self.badgearray[j]:SetName(string.sub(namestr,1,8))
			    else
			    	self.badgearray[j]:SetName(namestr)
			    end
            end
		end
		GLOBAL.ThePlayer.UpdateBadgeVisibility()
	end
end

-- Apply function on construction of class statusdisplays
AddClassPostConstruct("widgets/statusdisplays", onstatusdisplaysconstruct)

--server functions
local function onhealthdelta(inst, data)
	--get health of char
	local setpercent = data.newpercent and data.newpercent or 0
	inst.customhpbadgepercent:set(math.floor(setpercent * 100+0.5))--potatoey rounding to push shorts
	--get max health of char
	inst.customhpbadgemax:set(inst.components.health.maxhealth)
	--get debuff of char health
	inst.customhpbadgedebuff:set(inst.components.health:GetPenaltyPercent())
end

local function ondisconnect(inst,data)
	print("Event: Player dcd")
	--inst.disconnect:set(true)
	--GLOBAL.ThePlayer.components.health:DoDelta(0)
end

local function ondeath(inst,data)
	print("Event: "..inst:GetDisplayName().." died")
	inst.customisdead:set(true)
end

local function onrespawn(inst,data)
	print("Event: "..inst:GetDisplayName().." respawned")
	inst.customisdead:set(false)
end

local function ontimerdone(inst, data)
	for i, v in ipairs(GLOBAL.AllPlayers) do
		--inst.customisdead:set(false)
		if v:HasTag('playerghost') then
			v.customisdead:set(true)
		end
	end
end

--network functions

-- When somebody's health changes, it triggers the badges health update
local function oncustomhpbadgedirty(inst)
	if not GLOBAL.ThePlayer then return true end
	GLOBAL.ThePlayer.UpdateBadges()
end

--when someone dies or revives, it triggers badge visibility toggle
local function ondeathdeltadirty(inst)
	if not GLOBAL.ThePlayer then return true end
	GLOBAL.ThePlayer.UpdateBadges()
end

--when somebody disconnects, it triggers updating the player list
local function ondisconnectdirty(inst)
	if not GLOBAL.ThePlayer then return true end
	GLOBAL.ThePlayer.UpdateBadges()
end

local function customhppostinit(inst)
	-- Net variable that stores between 0-255; more info in netvars.lua
	-- GUID of entity, unique identifier of variable, event pushed when variable changes
	-- Event is pushed to the entity it refers to, server and client side wise

	inst.customhpbadgepercent = _G.net_byte(inst.GUID, "customhpbadge.percent", "customhpbadgedirty")
	inst.customhpbadgemax = _G.net_byte(inst.GUID,"customhpbadge.max","customhpbadgedirty")
	inst.customhpbadgedebuff = _G.net_byte(inst.GUID,"customhpbadge.debuff","customhpbadgedirty")
	inst.customisdead = _G.net_bool(inst.GUID,"customhpbadge.isdead","ondeathdeltadirty")

	-- Server (master simulation) reacts to health and changes the net variable
	if GLOBAL.TheWorld.ismastersim then
		inst:ListenForEvent("healthdelta", onhealthdelta)	
		inst:ListenForEvent("respawnfromghost", onrespawn)
		inst:ListenForEvent("death", ondeath)
        inst:ListenForEvent("respawnfromcorpse", onrespawn)
		--inst:ListenForEvent("playerexited",ondisconnect,GLOBAL.TheWorld)

		inst.components.health:DoDelta(0)

		--the below is just awful never do this unless you like dissapointing 7k subscribers but like w/e uuggghhhh
		inst:AddComponent("timer")
		inst:ListenForEvent("timerdone", ontimerdone)
		inst.components.timer:StartTimer("",1)

	end

	-- Dedicated server is dummy player, only players hosting or clients have the badges
	-- Only them react to the event pushed when the net variable changes
	if not GLOBAL.TheNet:IsDedicated() then
		inst:ListenForEvent("customhpbadgedirty", oncustomhpbadgedirty)
		inst:ListenForEvent("ondeathdeltadirty", ondeathdeltadirty)

	end
end
-- Apply function on player entity post initialization
AddPlayerPostInit(customhppostinit)

